package org.gdstash.ui.character;

import org.gdstash.character.GDChar;
import org.gdstash.ui.GDStashFrame;
import org.gdstash.ui.select.CharLenDocFilter;
import org.gdstash.ui.select.IntLenDocFilter;
import org.gdstash.ui.util.AdjustablePanel;
import org.gdstash.util.GDMsgFormatter;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.text.AbstractDocument;
import javax.swing.text.DocumentFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class GDCharDataPane extends AdjustablePanel {
    public static final int SEL_SEX_FEMALE = 0;
    public static final int SEL_SEX_MALE = 1;
    public static final int SEL_CAMPAIGN_DIFF_NORMAL = 0;
    public static final int SEL_CAMPAIGN_DIFF_ELITE = 1;
    public static final int SEL_CAMPAIGN_DIFF_ULTIMATE = 2;
    public static final int SEL_CRUCIBLE_DIFF_ASPIRANT = 0;
    public static final int SEL_CRUCIBLE_DIFF_CHALLENGER = 1;
    public static final int SEL_CRUCIBLE_DIFF_GLADIATOR = 2;
    private static String[] sexes;
    private static String[] campaignDiffs;
    private static String[] crucibleDiffs;
    private JLabel lblCharName;
    private JLabel lblMod;
    private JLabel lblSex;
    private JLabel lblHardcore;
    private JLabel lblDeaths;
    private JLabel lblMaxCampaignDifficulty;
    private JLabel lblMaxCrucibleDifficulty;
    private JLabel lblExperience;
    private JLabel lblLevel;
    private JLabel lblMoney;
    private JFormattedTextField ftCharName;
    private JCheckBox cbMod;
    private JComboBox<String> cbSex;
    private JCheckBox cbHardcore;
    private JTextField ftDeaths;
    private JComboBox<String> cbMaxCampaignDifficulty;
    private JComboBox<String> cbMaxCrucibleDifficulty;
    private JTextField ftExperience;
    private JTextField ftLevel;
    private JTextField ftMoney;
    private int oldLevel;
    private JPanel pnlMain;
    private GDCharStatEditPane editPane;
    private GDCharEditTabbedPane tabPane;

    static {
        GDCharDataPane.sexes = null;
        GDCharDataPane.campaignDiffs = null;
        GDCharDataPane.crucibleDiffs = null;
        GDCharDataPane.sexes = new String[2];
        GDCharDataPane.campaignDiffs = new String[3];
        GDCharDataPane.crucibleDiffs = new String[3];
        loadCBText();
    }

    public GDCharDataPane(final GDCharEditTabbedPane tabPane, final GDCharStatEditPane editPane) {
        this.tabPane = tabPane;
        this.editPane = editPane;
        this.adjustUI();
        GroupLayout layout = null;
        GroupLayout.SequentialGroup hGroup = null;
        GroupLayout.SequentialGroup vGroup = null;
        layout = new GroupLayout(this);
        this.setLayout(layout);
        layout.setAutoCreateGaps(true);
        layout.setAutoCreateContainerGaps(true);
        hGroup = layout.createSequentialGroup();
        hGroup.addGroup(layout.createParallelGroup().addComponent(this.lblCharName).addComponent(this.lblMod).addComponent(this.lblSex).addComponent(this.lblHardcore).addComponent(this.lblDeaths).addComponent(this.lblMaxCampaignDifficulty).addComponent(this.lblMaxCrucibleDifficulty).addComponent(this.lblExperience).addComponent(this.lblLevel).addComponent(this.lblMoney)).addGroup(layout.createParallelGroup().addComponent(this.ftCharName).addComponent(this.cbMod).addComponent(this.cbSex).addComponent(this.cbHardcore).addComponent(this.ftDeaths).addComponent(this.cbMaxCampaignDifficulty).addComponent(this.cbMaxCrucibleDifficulty).addComponent(this.ftExperience).addComponent(this.ftLevel).addComponent(this.ftMoney));
        layout.setHorizontalGroup(hGroup);
        vGroup = layout.createSequentialGroup();
        vGroup.addGroup(layout.createParallelGroup().addComponent(this.lblCharName).addComponent(this.ftCharName)).addGroup(layout.createParallelGroup().addComponent(this.lblMod).addComponent(this.cbMod)).addGroup(layout.createParallelGroup().addComponent(this.lblSex).addComponent(this.cbSex)).addGroup(layout.createParallelGroup().addComponent(this.lblHardcore).addComponent(this.cbHardcore)).addGroup(layout.createParallelGroup().addComponent(this.lblDeaths).addComponent(this.ftDeaths)).addGroup(layout.createParallelGroup().addComponent(this.lblMaxCampaignDifficulty).addComponent(this.cbMaxCampaignDifficulty)).addGroup(layout.createParallelGroup().addComponent(this.lblMaxCrucibleDifficulty).addComponent(this.cbMaxCrucibleDifficulty)).addGroup(layout.createParallelGroup().addComponent(this.lblExperience).addComponent(this.ftExperience)).addGroup(layout.createParallelGroup().addComponent(this.lblLevel).addComponent(this.ftLevel)).addGroup(layout.createParallelGroup().addComponent(this.lblMoney).addComponent(this.ftMoney));
        layout.setVerticalGroup(vGroup);
        layout.linkSize(0, this.lblCharName, this.lblMod);
        layout.linkSize(0, this.lblCharName, this.lblSex);
        layout.linkSize(0, this.lblCharName, this.lblHardcore);
        layout.linkSize(0, this.lblCharName, this.lblDeaths);
        layout.linkSize(0, this.lblCharName, this.lblMaxCampaignDifficulty);
        layout.linkSize(0, this.lblCharName, this.lblMaxCrucibleDifficulty);
        layout.linkSize(0, this.lblCharName, this.lblExperience);
        layout.linkSize(0, this.lblCharName, this.lblLevel);
        layout.linkSize(0, this.lblCharName, this.lblMoney);
        layout.linkSize(0, this.ftCharName, this.cbMod);
        layout.linkSize(0, this.ftCharName, this.cbSex);
        layout.linkSize(0, this.ftCharName, this.cbHardcore);
        layout.linkSize(0, this.ftCharName, this.ftDeaths);
        layout.linkSize(0, this.ftCharName, this.cbMaxCampaignDifficulty);
        layout.linkSize(0, this.ftCharName, this.cbMaxCrucibleDifficulty);
        layout.linkSize(0, this.ftCharName, this.ftExperience);
        layout.linkSize(0, this.ftCharName, this.ftLevel);
        layout.linkSize(0, this.ftCharName, this.ftMoney);
        layout.linkSize(1, this.lblCharName, this.lblMod);
        layout.linkSize(1, this.lblCharName, this.lblSex);
        layout.linkSize(1, this.lblCharName, this.lblHardcore);
        layout.linkSize(1, this.lblCharName, this.lblDeaths);
        layout.linkSize(1, this.lblCharName, this.lblMaxCampaignDifficulty);
        layout.linkSize(1, this.lblCharName, this.lblMaxCrucibleDifficulty);
        layout.linkSize(1, this.lblCharName, this.lblExperience);
        layout.linkSize(1, this.lblCharName, this.lblLevel);
        layout.linkSize(1, this.lblCharName, this.lblMoney);
        layout.linkSize(1, this.lblCharName, this.ftCharName);
        layout.linkSize(1, this.lblCharName, this.cbMod);
        layout.linkSize(1, this.lblCharName, this.cbSex);
        layout.linkSize(1, this.lblCharName, this.cbHardcore);
        layout.linkSize(1, this.lblCharName, this.ftDeaths);
        layout.linkSize(1, this.lblCharName, this.cbMaxCampaignDifficulty);
        layout.linkSize(1, this.lblCharName, this.cbMaxCrucibleDifficulty);
        layout.linkSize(1, this.lblCharName, this.ftExperience);
        layout.linkSize(1, this.lblCharName, this.ftLevel);
        layout.linkSize(1, this.lblCharName, this.ftMoney);
    }

    @Override
    public void adjustUI() {
        Font fntLabel = UIManager.getDefaults().getFont("Label.font");
        Font fntButton = UIManager.getDefaults().getFont("Button.font");
        if (fntButton == null) {
            fntButton = fntLabel;
        }
        Font fntCheck = UIManager.getDefaults().getFont("CheckBox.font");
        if (fntCheck == null) {
            fntCheck = fntLabel;
        }
        Font fntCombo = UIManager.getDefaults().getFont("ComboBox.font");
        if (fntCombo == null) {
            fntCombo = fntLabel;
        }
        Font fntFText = UIManager.getDefaults().getFont("FormattedTextField.font");
        if (fntFText == null) {
            fntFText = fntLabel;
        }
        Font fntBorder = UIManager.getDefaults().getFont("TitledBorder.font");
        if (fntBorder == null) {
            fntBorder = fntLabel;
        }
        fntLabel = fntLabel.deriveFont((float) GDStashFrame.iniConfig.sectUI.fontSize);
        fntButton = fntButton.deriveFont((float) GDStashFrame.iniConfig.sectUI.fontSize);
        fntCheck = fntCheck.deriveFont((float) GDStashFrame.iniConfig.sectUI.fontSize);
        fntCombo = fntCombo.deriveFont((float) GDStashFrame.iniConfig.sectUI.fontSize);
        fntFText = fntFText.deriveFont((float) GDStashFrame.iniConfig.sectUI.fontSize);
        fntBorder = fntBorder.deriveFont((float) GDStashFrame.iniConfig.sectUI.fontSize);
        final Border lowered = BorderFactory.createEtchedBorder(1);
        final Border raised = BorderFactory.createEtchedBorder(0);
        final Border compound = BorderFactory.createCompoundBorder(raised, lowered);
        final TitledBorder text = BorderFactory.createTitledBorder(compound, GDMsgFormatter.getString(GDMsgFormatter.rbGD, "TXT_CHAR_DATA"));
        text.setTitleFont(fntBorder);
        this.setBorder(text);
        loadCBText();
        if (this.lblCharName == null) {
            this.lblCharName = new JLabel();
        }
        this.lblCharName.setText(GDMsgFormatter.getString(GDMsgFormatter.rbGD, "TXT_CHAR_NAME"));
        this.lblCharName.setFont(fntLabel);
        if (this.ftCharName == null) {
            this.ftCharName = new JFormattedTextField();
            final DocumentFilter filter = new CharLenDocFilter(30);
            final AbstractDocument doc = (AbstractDocument) this.ftCharName.getDocument();
            doc.setDocumentFilter(filter);
        }
        this.ftCharName.setFont(fntFText);
        if (this.lblMod == null) {
            this.lblMod = new JLabel();
        }
        this.lblMod.setText(GDMsgFormatter.getString(GDMsgFormatter.rbGD, "TXT_CHAR_MODDED"));
        this.lblMod.setFont(fntLabel);
        if (this.cbMod == null) {
            this.cbMod = new JCheckBox();
        }
        this.cbMod.setFont(fntCheck);
        if (this.lblSex == null) {
            this.lblSex = new JLabel();
        }
        this.lblSex.setText(GDMsgFormatter.getString(GDMsgFormatter.rbGD, "TXT_CHAR_SEX"));
        this.lblSex.setFont(fntLabel);
        if (this.cbSex == null) {
            this.cbSex = new JComboBox<String>(GDCharDataPane.sexes);
        } else {
            this.updateLanguage(this.cbSex);
        }
        this.cbSex.setFont(fntCombo);
        this.cbSex.setMaximumSize(new Dimension(1000, 3 * GDStashFrame.iniConfig.sectUI.fontSize));
        if (this.lblHardcore == null) {
            this.lblHardcore = new JLabel();
        }
        this.lblHardcore.setText(GDMsgFormatter.getString(GDMsgFormatter.rbGD, "TXT_CHAR_HARDCORE"));
        this.lblHardcore.setFont(fntLabel);
        if (this.cbHardcore == null) {
            this.cbHardcore = new JCheckBox();
        }
        this.cbHardcore.setFont(fntCheck);
        if (this.lblDeaths == null) {
            this.lblDeaths = new JLabel();
        }
        this.lblDeaths.setText(GDMsgFormatter.getString(GDMsgFormatter.rbGD, "TXT_CHAR_STAT_DEATHS"));
        this.lblDeaths.setFont(fntLabel);
        if (this.ftDeaths == null) {
            this.ftDeaths = new JFormattedTextField();
            final DocumentFilter filter = new IntLenDocFilter(4);
            final AbstractDocument doc = (AbstractDocument) this.ftDeaths.getDocument();
            doc.setDocumentFilter(filter);
        }
        this.ftDeaths.setFont(fntFText);
        if (this.lblMaxCampaignDifficulty == null) {
            this.lblMaxCampaignDifficulty = new JLabel();
        }
        this.lblMaxCampaignDifficulty.setText(GDMsgFormatter.getString(GDMsgFormatter.rbGD, "TXT_CHAR_DIFFICULTY_MAX"));
        this.lblMaxCampaignDifficulty.setFont(fntLabel);
        if (this.cbMaxCampaignDifficulty == null) {
            this.cbMaxCampaignDifficulty = new JComboBox<String>(GDCharDataPane.campaignDiffs);
        } else {
            this.updateLanguage(this.cbMaxCampaignDifficulty);
        }
        this.cbMaxCampaignDifficulty.setFont(fntCombo);
        this.cbMaxCampaignDifficulty.setMaximumSize(new Dimension(1000, 3 * GDStashFrame.iniConfig.sectUI.fontSize));
        if (this.lblMaxCrucibleDifficulty == null) {
            this.lblMaxCrucibleDifficulty = new JLabel();
        }
        this.lblMaxCrucibleDifficulty.setText(GDMsgFormatter.getString(GDMsgFormatter.rbGD, "TXT_CHAR_DIFFICULTY_MAX_CRUCIBLE"));
        this.lblMaxCrucibleDifficulty.setFont(fntLabel);
        if (this.cbMaxCrucibleDifficulty == null) {
            this.cbMaxCrucibleDifficulty = new JComboBox<String>(GDCharDataPane.crucibleDiffs);
        } else {
            this.updateLanguage(this.cbMaxCrucibleDifficulty);
        }
        this.cbMaxCrucibleDifficulty.setFont(fntCombo);
        this.cbMaxCrucibleDifficulty.setMaximumSize(new Dimension(1000, 3 * GDStashFrame.iniConfig.sectUI.fontSize));
        if (this.lblExperience == null) {
            this.lblExperience = new JLabel();
        }
        this.lblExperience.setText(GDMsgFormatter.getString(GDMsgFormatter.rbGD, "TXT_CHAR_EXPERIENCE"));
        this.lblExperience.setFont(fntLabel);
        if (this.ftExperience == null) {
            this.ftExperience = new JFormattedTextField();
            final DocumentFilter filter = new IntLenDocFilter(9);
            final AbstractDocument doc = (AbstractDocument) this.ftExperience.getDocument();
            doc.setDocumentFilter(filter);
            this.ftExperience.addActionListener(new XPActionListener());
        }
        this.ftExperience.setFont(fntFText);
        if (this.lblLevel == null) {
            this.lblLevel = new JLabel();
        }
        this.lblLevel.setText(GDMsgFormatter.getString(GDMsgFormatter.rbGD, "TXT_CHAR_LEVEL"));
        this.lblLevel.setFont(fntLabel);
        if (this.ftLevel == null) {
            this.ftLevel = new JFormattedTextField();
            final DocumentFilter filter = new IntLenDocFilter(3);
            final AbstractDocument doc = (AbstractDocument) this.ftLevel.getDocument();
            doc.setDocumentFilter(filter);
            this.ftLevel.addActionListener(new LevelActionListener());
        }
        this.ftLevel.setFont(fntFText);
        if (this.lblMoney == null) {
            this.lblMoney = new JLabel();
        }
        this.lblMoney.setText(GDMsgFormatter.getString(GDMsgFormatter.rbGD, "TXT_CHAR_MONEY"));
        this.lblMoney.setFont(fntLabel);
        if (this.ftMoney == null) {
            this.ftMoney = new JFormattedTextField();
            final DocumentFilter filter = new IntLenDocFilter(9);
            final AbstractDocument doc = (AbstractDocument) this.ftMoney.getDocument();
            doc.setDocumentFilter(filter);
        }
        this.ftMoney.setFont(fntFText);
    }

    private void updateLanguage(final JComboBox<String> cb) {
        String[] texts = null;
        if (cb == this.cbSex) {
            texts = GDCharDataPane.sexes;
        }
        if (cb == this.cbMaxCampaignDifficulty) {
            texts = GDCharDataPane.campaignDiffs;
        }
        if (cb == this.cbMaxCrucibleDifficulty) {
            texts = GDCharDataPane.crucibleDiffs;
        }
        if (texts != null) {
            final int index = cb.getSelectedIndex();
            cb.removeAllItems();
            for (int i = 0; i < texts.length; ++i) {
                cb.addItem(texts[i]);
            }
            cb.setSelectedIndex(index);
        }
    }

    private void updateLevelDependencies(final int level) {
        if (this.oldLevel != level) {
            final int statPoints = this.editPane.getStatPoints();
            int statDelta = GDStashFrame.engineLevel.getStatPointsForRange(this.oldLevel, level);
            final int skillPoints = this.tabPane.getSkillPoints();
            int skillDelta = GDStashFrame.engineLevel.getSkillPointsForRange(this.oldLevel, level);
            if (this.oldLevel > level) {
                if (statDelta > statPoints) {
                    statDelta = statPoints;
                }
                if (skillDelta > skillPoints) {
                    skillDelta = skillPoints;
                }
                statDelta *= -1;
                skillDelta *= -1;
            }
            this.editPane.setStatPoints(statPoints + statDelta);
            this.tabPane.setSkillPoints(skillPoints + skillDelta);
            this.oldLevel = level;
        }
    }

    public void setChar(final GDChar gdc) {
        if (gdc == null) {
            this.ftCharName.setText("");
            this.cbMod.setSelected(false);
            this.cbSex.setSelectedIndex(1);
            this.cbHardcore.setSelected(false);
            this.ftDeaths.setText("0");
            this.cbMaxCampaignDifficulty.setSelectedIndex(0);
            this.cbMaxCrucibleDifficulty.setSelectedIndex(0);
            this.ftExperience.setText("0");
            this.ftLevel.setText("0");
            this.ftMoney.setText("0");
        } else {
            this.ftCharName.setText(gdc.getCharName());
            this.cbMod.setSelected(!gdc.isInMainQuest());
            this.cbSex.setSelectedIndex(gdc.getSex());
            this.cbHardcore.setSelected(gdc.isHardcore());
            this.ftDeaths.setText(Integer.toString(gdc.getDeaths()));
            this.cbMaxCampaignDifficulty.setSelectedIndex(gdc.getGreatestCampaignDifficulty());
            byte crucibleDifficulty = 0;
            switch (gdc.getGreatestCrucibleDifficulty()) {
                case 0: {
                    crucibleDifficulty = 0;
                    break;
                }
                case 1: {
                    crucibleDifficulty = 1;
                    break;
                }
                case 2: {
                    crucibleDifficulty = 2;
                    break;
                }
            }
            this.cbMaxCrucibleDifficulty.setSelectedIndex(crucibleDifficulty);
            this.ftExperience.setText(Integer.toString(gdc.getExperience()));
            this.ftLevel.setText(Integer.toString(gdc.getLevel()));
            this.ftMoney.setText(Integer.toString(gdc.getMoney()));
            this.oldLevel = Integer.parseInt(this.ftLevel.getText());
        }
    }

    public void updateChar(final GDChar gdc) {
        if (gdc == null) {
            return;
        }
        gdc.setCharName(this.ftCharName.getText());
        gdc.setInMainQuest(!this.cbMod.isSelected());
        gdc.setSex((byte) this.cbSex.getSelectedIndex());
        gdc.setHardcore(this.cbHardcore.isSelected());
        gdc.setDeaths(Integer.parseInt(this.ftDeaths.getText()));
        gdc.setGreatestCampaignDifficulty((byte) this.cbMaxCampaignDifficulty.getSelectedIndex());
        byte crucibleDifficulty = 0;
        switch (this.cbMaxCrucibleDifficulty.getSelectedIndex()) {
            case 0: {
                crucibleDifficulty = 0;
                break;
            }
            case 1: {
                crucibleDifficulty = 1;
                break;
            }
            case 2: {
                crucibleDifficulty = 2;
                break;
            }
        }
        gdc.setGreatestCrucibleDifficulty(crucibleDifficulty);
        gdc.setExperience(Integer.parseInt(this.ftExperience.getText()));
        gdc.setLevel(Integer.parseInt(this.ftLevel.getText()));
        gdc.setMoney(Integer.parseInt(this.ftMoney.getText()));
    }

    public String getCharName() {
        return this.ftCharName.getText();
    }

    private static void loadCBText() {
        GDCharDataPane.sexes[0] = GDMsgFormatter.getString(GDMsgFormatter.rbUI, "TXT_CHAR_SEX_FEMALE");
        GDCharDataPane.sexes[1] = GDMsgFormatter.getString(GDMsgFormatter.rbUI, "TXT_CHAR_SEX_MALE");
        GDCharDataPane.campaignDiffs[0] = GDMsgFormatter.getString(GDMsgFormatter.rbUI, "TXT_DIFF_NORMAL");
        GDCharDataPane.campaignDiffs[1] = GDMsgFormatter.getString(GDMsgFormatter.rbUI, "TXT_DIFF_ELITE");
        GDCharDataPane.campaignDiffs[2] = GDMsgFormatter.getString(GDMsgFormatter.rbUI, "TXT_DIFF_ULTIMATE");
        GDCharDataPane.crucibleDiffs[0] = GDMsgFormatter.getString(GDMsgFormatter.rbUI, "TXT_DIFF_ASPIRANT");
        GDCharDataPane.crucibleDiffs[1] = GDMsgFormatter.getString(GDMsgFormatter.rbUI, "TXT_DIFF_CHALLENGER");
        GDCharDataPane.crucibleDiffs[2] = GDMsgFormatter.getString(GDMsgFormatter.rbUI, "TXT_DIFF_GLADIATOR");
    }

    private class LevelActionListener implements ActionListener {
        @Override
        public void actionPerformed(final ActionEvent ev) {
            if (GDStashFrame.enginePlayer == null) {
                return;
            }
            final JTextField textField = (JTextField) ev.getSource();
            final int level = Integer.parseInt(textField.getText());
            final int xp = GDStashFrame.enginePlayer.getPlayerXPByLevel(level);
            GDCharDataPane.this.ftExperience.setText(Integer.toString(xp));
            GDCharDataPane.this.updateLevelDependencies(level);
        }
    }

    private class XPActionListener implements ActionListener {
        @Override
        public void actionPerformed(final ActionEvent ev) {
            if (GDStashFrame.enginePlayer == null) {
                return;
            }
            final JTextField textField = (JTextField) ev.getSource();
            final int xp = Integer.parseInt(textField.getText());
            final int level = GDStashFrame.enginePlayer.getPlayerLevelByXP(xp);
            GDCharDataPane.this.ftLevel.setText(Integer.toString(level));
            GDCharDataPane.this.updateLevelDependencies(level);
        }
    }
}
